@using System
@using System.Linq
@using ApiGenerator.Domain
@using ApiGenerator
@using ApiGenerator.Configuration.Overrides
@inherits CodeTemplatePage<RestApiSpec>
@{ await IncludeAsync("GeneratorNotice.cshtml", Model); }
@functions {
	private const string RawSize = "Raw";
	private const string SizeEnum = "Size";
	private static GlobalOverrides GlobalOverrides = new GlobalOverrides();

	private string CreateEnum(string enumName, string value, int? i)
	{
		var enumValue = (enumName == SizeEnum && value == string.Empty) ? RawSize : value.ToPascalCase(true);
		var enumCsharp = string.Format("[EnumMember(Value = \"{0}\")] {1}{2}", value, enumValue, i.HasValue ? " = 1 << " + i.Value : null);
		if (GlobalOverrides.ObsoleteEnumMembers.TryGetValue(enumName, out var d) && d.TryGetValue(value, out var obsolete))
		{
			return string.Format("[Obsolete(\"{0}\")]{2}\t\t{1}", obsolete, enumCsharp, Environment.NewLine);
		}
		return enumCsharp;
	}
	private string CreateCase(string e, string o)
	{
		var enumValue = GetEnumValue(e, o);
		return string.Format("case {0}.{1}: return \"{2}\";", e, enumValue, o);
	}
	private bool IsFlag(string name)
	{
		return name.EndsWith("Metric") || name.EndsWith("Feature");
	}

	private string GetEnumValue(string enumName, string value)
	{
		return enumName == SizeEnum && value == string.Empty 
			? RawSize 
			: value.ToPascalCase(true);
	}
}
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;

namespace Elasticsearch.Net
{
@foreach (EnumDescription e in Model.EnumsInTheSpec)
{
	var isFlag = IsFlag(e.Name);
	<text>
	@(isFlag ? "[Flags, StringEnum]" : "[StringEnum]")public enum @e.Name
	{
		@Raw(string.Join(","+ Environment.NewLine + "\t\t", e.Options.OrderBy(s => s == "_all" ? 1 : 0).Select((s, i) => CreateEnum(e.Name, s, isFlag ? (int?)i : null))))
	}</text>
}

	public static class KnownEnums
	{
		private static readonly @(Raw("ConcurrentDictionary<Type, Func<Enum, string>>")) EnumStringResolvers = new @(Raw("ConcurrentDictionary<Type, Func<Enum, string>>"))();

		static KnownEnums()
		{
		@foreach (EnumDescription e in Model.EnumsInTheSpec)
		{
<text>			EnumStringResolvers.TryAdd(typeof(@(e.Name)), (e) => GetStringValue((@(e.Name))e));
</text>
		}
		}

	@foreach (EnumDescription e in Model.EnumsInTheSpec)
	{
		var isFlag = IsFlag(e.Name);
		<text>
		public static string GetStringValue(this @(e.Name) enumValue)
		{
		</text>
		if (isFlag)
		{
			var allOption = e.Options.FirstOrDefault(o => o == "_all");
			if (allOption != null)
			{
<text>	if ((enumValue & @(e.Name).All) != 0) return "_all";
</text>
			}
<text>			var list = new @(Raw("List<string>()"));
</text>
			var g = GlobalOverrides.ObsoleteEnumMembers.TryGetValue(e.Name, out var d);
			foreach (var option in e.Options.Where(o => o != "_all"))
			{
				var value = GetEnumValue(e.Name, option);
				if (g && d.TryGetValue(option, out var _)) {
<text>#pragma warning disable 618
			if ((enumValue & @(e.Name).@(value)) != 0) list.Add("@(option)");
#pragma warning restore 618
</text>									
				}
				else {
<text>			if ((enumValue & @(e.Name).@(value)) != 0) list.Add("@(option)");
</text>
			    }                                                                                          
			}
<text>			return string.Join(",", list);
		}</text>
		}
		else
		{
			<text>	switch (enumValue)
			{
				@Raw(string.Join(Environment.NewLine + "\t\t\t\t", e.Options.Select(o => CreateCase(e.Name, o))))
			}
			throw new ArgumentException($"'{enumValue.ToString()}' is not a valid value for enum '@(e.Name)'");
		}</text>
		}
	}

	}
}